﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Axiom.Core;
using Axiom.Graphics;
using Axiom.Math;
using Axiom.Overlays;
using Axiom.Overlays.Elements;
using Engine.GuiDANCE;
using Engine.GuiDANCE.Components;
using Engine.Input;
using Engine.Navigation;

namespace Tools.Viewers.MeshViewer
{
    public class MeshViewer : GuiBase
    {
        private GuiCursor cursor;
        private Overlay gameOverlay;
        private NavigationManager navigation;
        private string fileName;
        private SceneNode objectNode;
        private SceneNode gridsNode;

        private RenderTypes renderType;
        public RenderTypes RenderType
        {
            get
            {
                return renderType;
            }
            set
            {
                renderType = value;
                renderTypeChanged = true;
            }
        }
        protected bool renderTypeChanged;

        private bool boundingBoxVisibility;
        public bool BoundingBoxVisibility
        {
            get
            {
                return boundingBoxVisibility;
            }
            set
            {
                boundingBoxVisibility = value;
                boundingBoxVisibilityChanged = true;
            }
        }
        protected bool boundingBoxVisibilityChanged;

        private bool gridsVisibility;
        public bool GridsVisibility
        {
            get
            {
                return gridsVisibility;
            }
            set
            {
                gridsVisibility = value;
                gridsVisibilityChanged = true;
            }
        }
        protected bool gridsVisibilityChanged;

        public MeshViewer(GuiRenderBox target, string fileName)
            : base(target)
        {
            GuiBase.RenderBox = target;
            this.fileName = fileName;
        }

        protected override void OnCreateWindow()
        {
            GuiBase.RenderWindow = window;
        }
        protected override void CreateScene()
        {
            engine.MaxFramesPerSecond = 30;
            gameOverlay = OverlayManager.Instance.GetByName("MeshViewer/GUI");
            List<string> subCursorList = new List<string>();
            subCursorList.Add("MeshViewer/GUI/CursorReleased");
            subCursorList.Add("MeshViewer/GUI/CursorGripped");

            cursor = new GuiCursor(
                (Panel)OverlayManager.Instance.Elements.GetElement("MeshViewer/GUI/Cursor"),
                subCursorList,
                0
            );

            gameOverlay.Show();
            GuiBase.Cursor = cursor;

            float meshRadius = 10f;
            float meshSize = 1f;
            float meshHeight = 0f;

            objectNode = scene.RootSceneNode.CreateChildSceneNode();
            if (fileName != null)
            {
                Mesh mesh = MeshManager.Instance.Load(fileName, ResourceGroupManager.DefaultResourceGroupName);
                Entity entity = scene.CreateEntity("Mesh", mesh);
                meshRadius = entity.BoundingRadius;
                meshSize = (float)Math.Max(entity.BoundingBox.Size.x, entity.BoundingBox.Size.z);
                meshHeight = entity.BoundingBox.Size.y * 0.5f;
                objectNode.AttachObject(entity);
                objectNode.Position -= entity.BoundingBox.Center;
                //objectNode.Position += Vector3.UnitY * meshHeight;
            }

            scene.AmbientLight = ColorEx.White;
            Light light = scene.CreateLight("Light");
            light.Type = LightType.Point;
            light.Position = (Vector3.UnitY) * meshRadius * 5;
            //light.SetAttenuation(100f, 1f, 0.001f, 0.000001f);
            light.Diffuse = ColorEx.Gray;
            light.Specular = ColorEx.White;
            scene.RootSceneNode.AttachObject(light);


            float gridSize = (float)Math.Pow(10d, Math.Max(0d, Math.Ceiling(Math.Log(meshSize, 10d)) - 1d));
            Mesh mGrids = createGrids(gridSize, meshHeight);
            gridsNode = scene.RootSceneNode.CreateChildSceneNode();
            Entity eGrids = scene.CreateEntity("Grids", mGrids);
            gridsNode.AttachObject(eGrids);

            navigation = new GlobeNavigationManager(scene, camera, input, userControl, meshRadius);
        }

        private Mesh createGrids(float size, float height)
        {
            ManualObject obj = new ManualObject("Grids");
            obj.Begin("MeshViewer/Grid", OperationType.LineList);
            for (int i = -10; i <= 10; i++)
            {
                obj.Position((((Vector3.UnitX * +10) + (Vector3.UnitZ * (float)i)) * size) - (Vector3.UnitY * height));
                obj.TextureCoord(0);
                obj.Position((((Vector3.UnitX * -10) + (Vector3.UnitZ * (float)i)) * size) - (Vector3.UnitY * height));
                obj.TextureCoord(0);
                obj.Position((((Vector3.UnitZ * +10) + (Vector3.UnitX * (float)i)) * size) - (Vector3.UnitY * height));
                obj.TextureCoord(0);
                obj.Position((((Vector3.UnitZ * -10) + (Vector3.UnitX * (float)i)) * size) - (Vector3.UnitY * height));
                obj.TextureCoord(0);
                if (i == 0)
                {
                    continue;
                }
                int offset = ((i + 10) * 4);
                obj.Index((ushort)(offset));
                obj.Index((ushort)(offset + 1));
                obj.Index((ushort)(offset + 2));
                obj.Index((ushort)(offset + 3));
            }
            obj.End();
            obj.Begin("MeshViewer/AxisX", OperationType.LineList);
            obj.Position(((Vector3.UnitX * +15) * size) - (Vector3.UnitY * height));
            obj.TextureCoord(0);
            obj.Position(((Vector3.UnitX * -15) * size) - (Vector3.UnitY * height));
            obj.TextureCoord(0);
            obj.Index(0);
            obj.Index(1);
            obj.End();
            obj.Begin("MeshViewer/AxisZ", OperationType.LineList);
            obj.Position(((Vector3.UnitZ * +15) * size) - (Vector3.UnitY * height));
            obj.TextureCoord(0);
            obj.Position(((Vector3.UnitZ * -15) * size) - (Vector3.UnitY * height));
            obj.TextureCoord(0);
            obj.Index(0);
            obj.Index(1);
            obj.End();
            return obj.ConvertToMesh("Grids", ResourceGroupManager.DefaultResourceGroupName);
        }

        protected override void CreateCamera()
        {
            // create a camera and initialize its position
            camera = scene.CreateCamera("Camera");
        }
        protected override bool OnFrameStarted(object source, FrameEventArgs e)
        {
            if (base.OnFrameStarted(source, e))
            {

                if (renderTypeChanged)
                {
                    if (RenderType == RenderTypes.Shaded)
                    {
                        camera.PolygonMode = PolygonMode.Solid;
                    }
                    else if (RenderType == RenderTypes.Wireframe)
                    {
                        camera.PolygonMode = PolygonMode.Wireframe;
                    }
                    else
                    {
                        camera.PolygonMode = PolygonMode.Points;
                    }
                    renderTypeChanged = false;
                }

                if (boundingBoxVisibilityChanged)
                {
                    objectNode.ShowBoundingBox = BoundingBoxVisibility;
                    boundingBoxVisibilityChanged = false;
                }

                if (gridsVisibilityChanged)
                {
                    gridsNode.IsVisible = GridsVisibility;
                    gridsVisibilityChanged = false;
                }
                navigation.Navigate(e);

                return true;
            }
            return false;
        }

        public override void Dispose()
        {
            base.Dispose();
        }
    }
}
